package com.jintian.smart.kernel.flowable.listener;

import com.jintian.smart.kernel.core.annotation.flow.FlowActionMoment;
import com.jintian.smart.kernel.core.flow.FlowAction;
import com.jintian.smart.kernel.core.flow.IFlowEventListener;
import com.jintian.smart.kernel.core.flow.IProcessContext;
import lombok.extern.slf4j.Slf4j;
import org.flowable.task.api.TaskInfo;

import java.util.*;

@Slf4j
public class FlowEventListenerManager {
    private Map<IFlowEventListener, Set<String>> listeners = new HashMap<>();

    public void registerListener(String process, String activity, String action, String moment, IFlowEventListener listener) {
        Set<String> regex = listeners.get(listener);
        if (regex == null) {
            regex = new HashSet<>();
            listeners.put(listener, regex);
        }
        String str = process + "@" + activity + "@" + action + "@" + moment;
        regex.add(str);
        log.debug("流程监听器{}触发正则:{}", listener.getClass(), str);
    }

    private List<IFlowEventListener> getListeners(String process, String activity, FlowAction action, FlowActionMoment.Moment moment) {
        String key = process + "@" + activity + "@" + action.name() + "@" + moment.name();
        List<IFlowEventListener> ret = new ArrayList<>();
        listeners.entrySet().forEach(e -> {
            Set<String> regexSet = e.getValue();
            for (String regex : regexSet) {
                if (key.matches(regex)) {
                    ret.add(e.getKey());
                }
            }
        });
        if (ret.size() > 1) {
            ret.sort(new Comparator<IFlowEventListener>() {
                @Override
                public int compare(IFlowEventListener o1, IFlowEventListener o2) {
                    return o2.priority() - o1.priority();
                }
            });
        }
        return ret;
    }

    public void triggerBeforeListener(String process, String activity, FlowAction action, IProcessContext context) {
        // 执行前
        List<IFlowEventListener> befores = this.getListeners(process, activity, action, FlowActionMoment.Moment.before);
        for (IFlowEventListener<List<TaskInfo>> listener : befores) {
            listener.bindProcessContext(context);
            listener.before(context);
        }
    }

    public void triggerAfterListener(String process, String activity, FlowAction action, IProcessContext context) {
        List<IFlowEventListener> afters = this.getListeners(process, activity, action, FlowActionMoment.Moment.after);
        for (IFlowEventListener<List<TaskInfo>> listener : afters) {
            listener.bindProcessContext(context);
            listener.after(context);
        }
    }

    public void unbindProcessContext(String process, String activity, FlowAction action) {
        List<IFlowEventListener> befores = this.getListeners(process, activity, action, FlowActionMoment.Moment.before);
        List<IFlowEventListener> afters = this.getListeners(process, activity, action, FlowActionMoment.Moment.after);

        for (IFlowEventListener listener : befores) {
            listener.unbindProcessContext();
        }
        for (IFlowEventListener listener : afters) {
            listener.unbindProcessContext();
        }
    }
}
